home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / news / inn1.000 / inn1.4sec-linux-src.tar / inn / nnrpd / post.c < prev   
C/C++ Source or Header  |  1993-01-29  |  20KB  |  798 lines

  1. /*  $Revision: 1.18 $
  2. **
  3. **  Check article, send it to the local server.
  4. */
  5. #include "nnrpd.h"
  6. #if    defined(DO_NEED_TIME)
  7. #include <time.h>
  8. #endif    /* defined(DO_NEED_TIME) */
  9. #include <sys/time.h>
  10.  
  11. #define FLUSH_ERROR(F)        (fflush((F)) == EOF || ferror((F)))
  12. #define HEADER_DELTA        20
  13.  
  14. typedef enum _HEADERTYPE {
  15.     HTobs,
  16.     HTreq,
  17.     HTstd
  18. } HEADERTYPE;
  19.  
  20. typedef struct _HEADER {
  21.     STRING    Name;
  22.     BOOL    CanSet;
  23.     HEADERTYPE    Type;
  24.     int        Size;
  25.     char    *Value;
  26. } HEADER;
  27.  
  28.  
  29. STATIC char    Error[SMBUF];
  30. STATIC char    NGSEPS[] = NG_SEPARATOR;
  31. STATIC char    **OtherHeaders;
  32. STATIC int    OtherCount;
  33. STATIC int    OtherSize;
  34. STATIC BOOL    WasMailed;
  35. STATIC STRING    BadDistribs[] = {
  36.     BAD_DISTRIBS
  37. };
  38.  
  39. STATIC HEADER    Table[] = {
  40.     /*     Name            Canset    Type    */
  41.     {    "Path",            TRUE,    HTstd },
  42. #define _path         0
  43.     {    "From",            TRUE,    HTreq },
  44. #define _from         1
  45.     {    "Newsgroups",        TRUE,    HTreq },
  46. #define _newsgroups     2
  47.     {    "Subject",        TRUE,    HTreq },
  48. #define _subject     3
  49.     {    "Control",        TRUE,    HTstd },
  50. #define _control     4
  51.     {    "Supersedes",        TRUE,    HTstd },
  52. #define _supersedes     5
  53.     {    "Followup-To",        TRUE,    HTstd },
  54. #define _followupto     6
  55.     {    "Date",            TRUE,    HTstd },
  56. #define _date         7
  57.     {    "Organization",        TRUE,    HTstd },
  58. #define _organization     8
  59.     {    "Lines",        TRUE,    HTstd },
  60. #define _lines         9
  61.     {    "Sender",        TRUE,    HTstd },
  62. #define _sender        10
  63.     {    "Approved",        TRUE,    HTstd },
  64. #define _approved    11
  65.     {    "Distribution",        TRUE,    HTstd },
  66. #define _distribution    12
  67.     {    "Expires",        TRUE,    HTstd },
  68. #define _expires    13
  69.     {    "Message-ID",        TRUE,    HTstd },
  70. #define _messageid    14
  71.     {    "References",        TRUE,    HTstd },
  72. #define _references    15
  73.     {    "Reply-To",        TRUE,    HTstd },
  74. #define _replyto    16
  75.     {    "NNTP-Posting-Host",    FALSE,    HTstd },
  76. #define _nntpposthost    17
  77.     {    "Mime-Version",        TRUE,    HTstd },
  78. #define _mimeversion    18
  79.     {    "Content-Type",        TRUE,    HTstd },
  80. #define _contenttype    19
  81.     {    "Content-Transfer-Encoding", TRUE, HTstd },
  82. #define _contenttransferencoding 20
  83.     {    "Xref",            FALSE,    HTstd },
  84.     {    "Summary",        TRUE,    HTstd },
  85.     {    "Keywords",        TRUE,    HTstd },
  86.     {    "Date-Received",    FALSE,    HTobs },
  87.     {    "Received",        FALSE,    HTobs },
  88.     {    "Posted",        FALSE,    HTobs },
  89.     {    "Posting-Version",    FALSE,    HTobs },
  90.     {    "Relay-Version",    FALSE,    HTobs },
  91. };
  92.  
  93. #define HDR(_x)    (Table[(_x)].Value)
  94.  
  95.  
  96.  
  97. /*
  98. **  Trim trailing spaces, return pointer to first non-space char.
  99. */
  100. STATIC char *
  101. TrimSpaces(p)
  102.     register char    *p;
  103. {
  104.     register char    *start;
  105.  
  106.     for (start = p; ISWHITE(*start); start++)
  107.     continue;
  108.     for (p = start + strlen(start); p > start && CTYPE(isspace, p[-1]); )
  109.     *--p = '\0';
  110.     return start;
  111. }
  112.  
  113.  
  114. /*
  115. **  Mark the end of the header starting at p, and return a pointer
  116. **  to the start of the next one or NULL.  Handles continuations.
  117. */
  118. STATIC char *
  119. NextHeader(p)
  120.     register char    *p;
  121. {
  122.     for ( ; (p = strchr(p, '\n')) != NULL; p++) {
  123.     if (ISWHITE(p[1]))
  124.         continue;
  125.     *p = '\0';
  126.     return p + 1;
  127.     }
  128.     return NULL;
  129. }
  130.  
  131.  
  132. /*
  133. **  Strip any headers off the article and dump them into the table.
  134. **  On error, return NULL and fill in Error.
  135. */
  136. STATIC char *
  137. StripOffHeaders(article)
  138.     char        *article;
  139. {
  140.     register char    *p;
  141.     register char    *q;
  142.     register HEADER    *hp;
  143.     register char    c;
  144.  
  145.     /* Scan through buffer, a header at a time. */
  146.     for (p = article; ; ) {
  147.  
  148.     /* See if it's a known header. */
  149.     c = CTYPE(islower, *p) ? toupper(*p) : *p;
  150.     for (hp = Table; hp < ENDOF(Table); hp++)
  151.         if (c == hp->Name[0]
  152.          && p[hp->Size] == ':'
  153.          && caseEQn(p, hp->Name, hp->Size)) {
  154.         if (hp->Type == HTobs) {
  155.             (void)sprintf(Error, "Obsolete \"%s\" header", hp->Name);
  156.             return NULL;
  157.         }
  158.         if (hp->Value) {
  159.             (void)sprintf(Error, "Duplicate \"%s\" header", hp->Name);
  160.             return NULL;
  161.         }
  162.         for (q = &p[hp->Size + 1]; ISWHITE(*q); q++)
  163.             continue;
  164.         hp->Value = q;
  165.         break;
  166.         }
  167.  
  168.     /* No; add it to the set of other headers. */
  169.     if (hp == ENDOF(Table)) {
  170.         if (OtherCount >= OtherSize - 1) {
  171.         OtherSize += HEADER_DELTA;
  172.         RENEW(OtherHeaders, char*, OtherSize);
  173.         }
  174.         OtherHeaders[OtherCount++] = p;
  175.     }
  176.  
  177.     /* Get start of next header; if it's a blank line, we hit the end. */
  178.     if ((p = NextHeader(p)) == NULL) {
  179.         (void)strcpy(Error, "Article has no body -- just headers");
  180.         return NULL;
  181.     }
  182.     if (*p == '\n')
  183.         break;
  184.     }
  185.  
  186.     return p + 1;
  187. }
  188.  
  189.  
  190.  
  191. /*
  192. **  Check the control message, and see if it's legit.  Return pointer to
  193. **  error message if not.
  194. */
  195. STATIC STRING
  196. CheckControl(ctrl)
  197.     char    *ctrl;
  198. {
  199.     register char    *p;
  200.     register char    *q;
  201.     char        save;
  202.  
  203.     /* Snip off the first word. */
  204.     for (p = ctrl; ISWHITE(*p); p++)
  205.     continue;
  206.     for (ctrl = p; *p && !ISWHITE(*p); p++)
  207.     continue;
  208.     if (p == ctrl)
  209.     return "Empty control message";
  210.     save = *p;
  211.     *p = '\0';
  212.  
  213.     if (EQ(ctrl, "cancel")) {
  214.     for (q = p + 1; ISWHITE(*q); q++)
  215.         continue;
  216.     if (*q == '\0')
  217.         return "Message-ID missing in cancel";
  218.     }
  219.     else if (EQ(ctrl, "sendsys") || EQ(ctrl, "senduuname")
  220.       || EQ(ctrl, "version") || EQ(ctrl, "checkgroups")
  221.       || EQ(ctrl, "ihave") || EQ(ctrl, "sendme")
  222.       || EQ(ctrl, "newgroup") || EQ(ctrl, "rmgroup"))
  223.     /* SUPPRESS 530 *//* Empty body for statement */
  224.     ;
  225.     else {
  226.     (void)sprintf(Error, "\"%s\" is not a valid control message",
  227.         ctrl);
  228.     return Error;
  229.     }
  230.     *p = save;
  231.     return NULL;
  232. }
  233.  
  234.  
  235. /*
  236. **  Check the Distribution header, and exit on error.
  237. */
  238. STATIC STRING
  239. CheckDistribution(p)
  240.     register char    *p;
  241. {
  242.     static char        SEPS[] = " \t,";
  243.     register STRING    *dp;
  244.  
  245.     if ((p = strtok(p, SEPS)) == NULL)
  246.     return "Can't parse Distribution line.";
  247.     do {
  248.     for (dp = BadDistribs; *dp; dp++)
  249.         if (wildmat(p, *dp)) {
  250.         (void)sprintf(Error, "Illegal distribution \"%s\"", p);
  251.         return Error;
  252.         }
  253.     } while ((p = strtok((char *)NULL, SEPS)) != NULL);
  254.     return NULL;
  255. }
  256.  
  257.  
  258. /*
  259. **  Process all the headers.  FYI, they're done in RFC-order.
  260. **  Return NULL if okay, or an error message.
  261. */
  262. STATIC STRING
  263. ProcessHeaders(linecount)
  264.     int            linecount;
  265. {
  266.     static char        MONTHS[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
  267.     static char        subjbuff[NNTP_STRLEN];
  268.     static char        datebuff[40];
  269.     static char        orgbuff[SMBUF];
  270.     static char        linebuff[40];
  271.     static char        mimeversion[SMBUF];
  272.     static char        mimetype[SMBUF];
  273.     static char        mimeencoding[SMBUF];
  274.     register HEADER    *hp;
  275.     register char    *p;
  276.     time_t        t;
  277.     struct tm        *gmt;
  278.     TIMEINFO        Now;
  279.     STRING        error;
  280.  
  281.     /* Do some preliminary fix-ups. */
  282.     for (hp = Table; hp < ENDOF(Table); hp++) {
  283.     if (!hp->CanSet && hp->Value) {
  284.         (void)sprintf(Error, "Can't set system \"%s\" header", hp->Name);
  285.         return Error;
  286.     }
  287.     if (hp->Value) {
  288.         hp->Value = TrimSpaces(hp->Value);
  289.         if (*hp->Value == '\0')
  290.         hp->Value = NULL;
  291.     }
  292.     }
  293.  
  294. #if    defined(DO_NNRP_AUTH_SENDER)
  295.     /* Zap the Sender? */
  296.     if (!PERMauthorized)
  297.     HDR(_sender) = NULL;
  298. #endif    /* defined(DO_NNRP_AUTH_SENDER) */
  299.  
  300.     /* Set Date. */
  301.     if (GetTimeInfo(&Now) < 0) {
  302.     (void)sprintf(Error, "Can't get the time, %s", strerror(errno));
  303.     return Error;
  304.     }
  305.  
  306.     if (HDR(_date) == NULL) {
  307.     if ((gmt = gmtime(&Now.time)) == NULL)
  308.         return "Can't get the time";
  309.     (void)sprintf(datebuff, "%d %3.3s %d %02.2d:%02.2d:%02.2d GMT",
  310.         gmt->tm_mday, &MONTHS[3 * gmt->tm_mon], 1900 + gmt->tm_year,
  311.         gmt->tm_hour, gmt->tm_min, gmt->tm_sec);
  312.     HDR(_date) = datebuff;
  313.     }
  314.     else {
  315.     if ((t = parsedate(HDR(_date), &Now)) == -1)
  316.         return "Can't parse \"Date\" header";
  317.     if (t > Now.time + DATE_FUZZ)
  318.         return "Article posted in the future";
  319.     }
  320.  
  321.     /* Newsgroups are checked later. */
  322.  
  323.     /* Set Subject; Control overrides the subject. */
  324.     if (HDR(_control)) {
  325.     if ((error = CheckControl(HDR(_control))) != NULL)
  326.         return error;
  327.     (void)sprintf(subjbuff, "cmsg %s", HDR(_control));
  328.     HDR(_subject) = subjbuff;
  329.     }
  330.     else {
  331.     p = HDR(_subject);
  332.     if (p == NULL)
  333.         return "Required \"Subject\" header is missing";
  334.     if (EQn(p, "cmsg ", 5)) {
  335.         HDR(_control) = p + 5;
  336.         if ((error = CheckControl(HDR(_control))) != NULL)
  337.         return error;
  338.     }
  339. #if    0
  340.     if (EQn(p, "Re: ", 4) && HDR(_references) == NULL)
  341.         return "Article starts with \"Re: \" but has no references";
  342. #endif    /* 0 */
  343.     }
  344.  
  345.     /* Set Message-ID */
  346.     if (HDR(_messageid) == NULL) {
  347.     if ((p = GenerateMessageID()) == NULL) {
  348.         (void)sprintf(Error, "Can't generate Message-ID, %s",
  349.             strerror(errno));
  350.         return Error;
  351.     }
  352.     HDR(_messageid) = p;
  353.     }
  354.  
  355.     /* Set Path */
  356.     if (HDR(_path) == NULL) {
  357.     /* Note that innd will put host name here for us. */
  358.     HDR(_path) = NEWSMASTER;
  359.     }
  360.  
  361.     /* Reply-To; left alone. */
  362.     /* Sender; set above. */
  363.  
  364.     /* Check Expires. */
  365.     if (HDR(_expires) && parsedate(HDR(_expires), &Now) == -1)
  366.     return "Can't parse \"Expires\" header";
  367.  
  368.     /* References; left alone. */
  369.     /* Control; checked above. */
  370.  
  371.     /* Distribution. */
  372.     if ((p = HDR(_distribution)) != NULL) {
  373.     p = COPY(p);
  374.     error = CheckDistribution(p);
  375.     DISPOSE(p);
  376.     if (error != NULL)
  377.         return error;
  378.     }
  379.  
  380.     /* Set Organization */
  381.     if (HDR(_organization) == NULL
  382.      && (p = GetConfigValue(_CONF_ORGANIZATION)) != NULL) {
  383.     (void)strcpy(orgbuff, p);
  384.     HDR(_organization) = orgbuff;
  385.     }
  386.  
  387.     /* Keywords; left alone. */
  388.     /* Summary; left alone. */
  389.     /* Approved; left alone. */
  390.  
  391.     /* MIME headers. */
  392.     if (HDR(_mimeversion) == NULL
  393.      && (p = GetConfigValue(_CONF_MIMEVERSION)) != NULL) {
  394.     (void)strcpy(mimeversion, p);
  395.     HDR(_mimeversion) = mimeversion;
  396.  
  397.     /* Set Content-Type */
  398.     if (HDR(_contenttype) == NULL) {
  399.         if ((p = GetConfigValue(_CONF_CONTENTTYPE)) == NULL)
  400.         return "Can't get \"Content-Type\" header";
  401.         (void)strcpy(mimetype, p);
  402.         HDR(_contenttype) = mimetype;
  403.     }
  404.  
  405.     /* Set Content-Transfer-Encoding */
  406.     if (HDR(_contenttransferencoding) == NULL) {
  407.         if ((p = GetConfigValue(_CONF_ENCODING)) == NULL)
  408.         return "Can't get \"Content-Transfer-Encoding\" header";
  409.         (void)strcpy(mimeencoding, p);
  410.         HDR(_contenttransferencoding) = mimeencoding;
  411.     }
  412.     }
  413.  
  414.     /* Set Lines */
  415.     (void)sprintf(linebuff, "%d", linecount);
  416.     HDR(_lines) = linebuff;
  417.  
  418.     /* Supersedes; left alone. */
  419.  
  420.     /* NNTP-Posting host; set. */
  421.     HDR(_nntpposthost) = ClientHost;
  422.  
  423.     /* Now make sure everything is there. */
  424.     for (hp = Table; hp < ENDOF(Table); hp++)
  425.     if (hp->Type == HTreq && hp->Value == NULL) {
  426.         (void)sprintf(Error, "Required \"%s\" header is missing",
  427.             hp->Name);
  428.         return Error;
  429.     }
  430.  
  431.     return NULL;
  432. }
  433.  
  434.  
  435. #if    defined(DO_CHECK_INCLUDED_TEXT)
  436. /*
  437. **  See if the user has more included text than new text.  Simple-minded, but
  438. **  reasonably effective for catching neophyte's mistakes.  A line starting
  439. **  with > is included text.  Decrement the count on lines starting with <
  440. **  so that we don't reject diff(1) output.
  441. */
  442. STATIC STRING
  443. CheckIncludedText(p, lines)
  444.     register char    *p;
  445.     register int    lines;
  446. {
  447.     register int    i;
  448.  
  449.     for (i = 0; ; p++) {
  450.     switch (*p) {
  451.     case '>':
  452.         i++;
  453.         break;
  454.     case '<':
  455.         i--;
  456.         break;
  457.     }
  458.     if ((p = strchr(p + 1, '\n')) == NULL)
  459.         break;
  460.     }
  461.     if (i * 2 > lines)
  462.     return "Article not posted -- more included text than new text";
  463.     return NULL;
  464. }
  465. #endif    /* defined(DO_CHECK_INCLUDED_TEXT) */
  466.  
  467.  
  468.  
  469. /*
  470. **  Try to mail an article to the moderator of the group.
  471. */
  472. STATIC STRING
  473. MailArticle(group, article)
  474.     char        *group;
  475.     char        *article;
  476. {
  477.     static char        CANTSEND[] = "Can't send text to mailer";
  478.     register FILE    *F;
  479.     register HEADER    *hp;
  480.     register int    i;
  481.     char        *address;
  482.     char        buff[SMBUF];
  483.  
  484.     /* Try to get the address first. */
  485.     if ((address = GetModeratorAddress(group)) == NULL) {
  486.     (void)sprintf(Error, "No mailing address for \"%s\" -- %s",
  487.         group, "ask your news administrator to fix this");
  488.     return Error;
  489.     }
  490.  
  491.     /* Now build up the command (ignore format/argument mismatch errors,
  492.      * in case %s isn't in _PATH_SENDMAIL) and send the headers. */
  493.     (void)sprintf(buff, _PATH_SENDMAIL, address);
  494.     if ((F = popen(buff, "w")) == NULL)
  495.     return "Can't start mailer";
  496.     (void)fprintf(F, "To: %s\n", address);
  497.     if (FLUSH_ERROR(F)) {
  498.     (void)pclose(F);
  499.     return CANTSEND;
  500.     }
  501.  
  502.     /* Write the headers, a blank line, then the article. */
  503.     for (hp = Table; hp < ENDOF(Table); hp++)
  504.     if (hp->Value) {
  505.         (void)fprintf(F, "%s: %s\n", hp->Name, hp->Value);
  506.         if (FLUSH_ERROR(F)) {
  507.         (void)pclose(F);
  508.         return CANTSEND;
  509.         }
  510.     }
  511.     for (i = 0; i < OtherCount; i++) {
  512.     (void)fprintf(F, "%s\n", OtherHeaders[i]);
  513.     if (FLUSH_ERROR(F)) {
  514.         (void)pclose(F);
  515.         return CANTSEND;
  516.     }
  517.     }
  518.     (void)fprintf(F, "\n");
  519.     i = strlen(article);
  520.     if (fwrite((POINTER)article, (SIZE_T)1, (SIZE_T)i, F) != i)
  521.     return "Can't send article";
  522.     if (FLUSH_ERROR(F)) {
  523.     (void)pclose(F);
  524.     return CANTSEND;
  525.     }
  526.     i = pclose(F);
  527.     if (i) {
  528.     (void)sprintf(Error, "Mailer exited with status %d -- %s",
  529.         i, "Article might not have been mailed");
  530.     return Error;
  531.     }
  532.     WasMailed = TRUE;
  533.     return NULL;
  534. }
  535.  
  536.  
  537. /*
  538. **  Check the newsgroups and make sure they're all valid, that none are
  539. **  moderated, etc.
  540. */
  541. STATIC STRING
  542. ValidNewsgroups(hdr, article)
  543.     char        *hdr;
  544.     char        *article;
  545. {
  546.     static char        distbuff[SMBUF];
  547.     register char    *groups;
  548.     register char    *p;
  549.     register GROUPENTRY    *gp;
  550.     register BOOL    approved;
  551.     struct _DDHANDLE    *h;
  552.     BOOL        IsNewgroup;
  553.     BOOL        FoundOne;
  554.  
  555.     p = HDR(_control);
  556.     IsNewgroup = p && EQn(p, "newgroup", 8);
  557.     groups = COPY(hdr);
  558.     if ((p = strtok(groups, NGSEPS)) == NULL)
  559.     return "Can't parse newsgroups line";
  560.  
  561.     /* Don't mail article if just checking Followup-To line. */
  562.     approved = HDR(_approved) != NULL || article == NULL;
  563.  
  564.     Error[0] = '\0';
  565.     FoundOne = FALSE;
  566.     h = DDstart((FILE *)NULL, (FILE *)NULL);
  567.     do {
  568. #if    defined(DO_MERGE_TO_GROUPS)
  569.     if (p[0] == 't' && p[1] == 'o' && p[2] == '.')
  570.         p = "to";
  571. #endif    /* defined(DO_MERGE_TO_GROUPS) */
  572.     if ((gp = GRPfind(p)) == NULL)
  573.         continue;
  574.     FoundOne = TRUE;
  575.     DDcheck(h, p);
  576.     switch (gp->Flag) {
  577.     case NF_FLAG_OK:
  578.         break;
  579.     case NF_FLAG_MODERATED:
  580.         if (!approved) {
  581.         DISPOSE(groups);
  582.         DISPOSE(DDend(h));
  583.         return MailArticle(gp->Name, article);
  584.         }
  585.         break;
  586.     case NF_FLAG_IGNORE:
  587.     case NF_FLAG_NOLOCAL:
  588.         (void)sprintf(Error, "Postings to \"%s\" are not allowed here.",
  589.             gp->Name);
  590.         break;
  591.     case NF_FLAG_EXCLUDED:
  592.         /* Do NOT return an error. */
  593.         break;
  594.     case NF_FLAG_ALIAS:
  595.         (void)sprintf(Error,
  596.             "The newsgroup \"%s\" has been renamed to \"%s\".\n",
  597.             p, gp->Alias);
  598.         break;
  599.     }
  600.     } while ((p = strtok((char *)NULL, NGSEPS)) != NULL);
  601.     DISPOSE(groups);
  602.  
  603.     if (!FoundOne && !IsNewgroup)
  604.     (void)sprintf(Error, "No such newsgroup as \"%s\"", p);
  605.     if (Error[0]) {
  606.     DISPOSE(DDend(h));
  607.     return Error;
  608.     }
  609.  
  610.     p = DDend(h);
  611.     if (HDR(_distribution) == NULL && *p) {
  612.     (void)strcpy(distbuff, p);
  613.     HDR(_distribution) = distbuff;
  614.     }
  615.     DISPOSE(p);
  616.     return NULL;
  617. }
  618.  
  619.  
  620. /*
  621. **  Send a quit message to the server, eat its reply.
  622. */
  623. STATIC void
  624. SendQuit(FromServer, ToServer)
  625.     FILE    *FromServer;
  626.     FILE    *ToServer;
  627. {
  628.     char    buff[NNTP_STRLEN];
  629.  
  630.     (void)fprintf(ToServer, "quit\r\n");
  631.     (void)fflush(ToServer);
  632.     (void)fclose(ToServer);
  633.     (void)fgets(buff, sizeof buff, FromServer);
  634.     (void)fclose(FromServer);
  635. }
  636.  
  637.  
  638. /*
  639. **  Offer the article to the server, return its reply.
  640. */
  641. STATIC int
  642. OfferArticle(buff, buffsize, FromServer, ToServer)
  643.     char        *buff;
  644.     int            buffsize;
  645.     FILE        *FromServer;
  646.     FILE        *ToServer;
  647. {
  648.     static char        CANTSEND[] = "Can't send %s to server, %s";
  649.  
  650.     (void)fprintf(ToServer, "ihave %s\r\n", HDR(_messageid));
  651.     if (FLUSH_ERROR(ToServer)
  652.      || fgets(buff, buffsize, FromServer) == NULL) {
  653.     (void)sprintf(buff, CANTSEND, "IHAVE", strerror(errno));
  654.     return -1;
  655.     }
  656.     return atoi(buff);
  657. }
  658.  
  659.  
  660. STRING
  661. ARTpost(article, idbuff)
  662.     char        *article;
  663.     char        *idbuff;
  664. {
  665.     static char        CANTSEND[] = "Can't send %s to server, %s";
  666.     register int    i;
  667.     register char    *p;
  668.     register char    *next;
  669.     register HEADER    *hp;
  670.     FILE        *ToServer;
  671.     FILE        *FromServer;
  672.     char        buff[NNTP_STRLEN + 2];
  673.     STRING        error;
  674.  
  675.     /* Set up the other headers list. */
  676.     if (OtherHeaders == NULL) {
  677.     OtherSize = HEADER_DELTA;
  678.     OtherHeaders = NEW(char*, OtherSize);
  679.     }
  680.  
  681.     /* Basic processing. */
  682.     OtherCount = 0;
  683.     WasMailed = FALSE;
  684.     for (hp = Table; hp < ENDOF(Table); hp++) {
  685.     hp->Size = strlen(hp->Name);
  686.     hp->Value = NULL;
  687.     }
  688.     if ((article = StripOffHeaders(article)) == NULL)
  689.     return Error;
  690.     for (i = 0, p = article; p; i++, p = next + 1)
  691.     if ((next = strchr(p, '\n')) == NULL)
  692.         break;
  693. #if    defined(DO_CHECK_INCLUDED_TEXT)
  694.     if ((error = CheckIncludedText(article, i)) != NULL)
  695.     return error;
  696. #endif    /* defined(DO_CHECK_INCLUDED_TEXT) */
  697.     if ((error = ProcessHeaders(i)) != NULL)
  698.     return error;
  699.     if (i == 0 && HDR(_control) == NULL)
  700.     return "Article is empty";
  701.     if ((error = ValidNewsgroups(HDR(_newsgroups), article)) != NULL
  702.      || WasMailed)
  703.     return error;
  704.     if ((p = HDR(_followupto)) != NULL
  705.      && !EQ(p, "poster")
  706.      && (error = ValidNewsgroups(p, (char *)NULL)) != NULL)
  707.     return error;
  708. #if    LOCAL_MAX_ARTSIZE > 0
  709.     if (strlen(article) > LOCAL_MAX_ARTSIZE) {
  710.     (void)sprintf(Error,
  711.         "Article is bigger then local limit of %ld bytes\n",
  712.         LOCAL_MAX_ARTSIZE);
  713.     return Error;
  714.     }
  715. #endif    /* LOCAL_MAX_ARTSIZE > 0 */
  716.  
  717.     /* Open a local connection to the server. */
  718.     if (RemoteMaster)
  719.     i = NNTPconnect(RemoteMaster, &FromServer, &ToServer, buff);
  720.     else {
  721. #if    defined(DO_HAVE_UNIX_DOMAIN)
  722.     i = NNTPlocalopen(&FromServer, &ToServer, buff);
  723. #else
  724.     i = NNTPremoteopen(&FromServer, &ToServer, buff);
  725. #endif    /* defined(DO_HAVE_UNIX_DOMAIN) */
  726.     }
  727.     if (i < 0) {
  728.     if (buff[0])
  729.         (void)strcpy(Error, buff);
  730.     else
  731.         (void)sprintf(Error, CANTSEND, "connect request", strerror(errno));
  732.     return Error;
  733.     }
  734.     if (Tracing)
  735.     syslog(L_TRACE, "%s post_connect %s", ClientHost, RemoteMaster);
  736.  
  737.     /* The code below has too many (void) casts for my tastes.  At least
  738.      * they are all inside cases that are most likely never going to
  739.      * happen -- for example, if the server crashes. */
  740.  
  741.     /* Offer article to server. */
  742.     i = OfferArticle(buff, sizeof buff, FromServer, ToServer);
  743.     if (i == NNTP_AUTH_NEEDED_VAL) {
  744.     /* Send authorization. */
  745.     if (NNTPsendpassword(RemoteMaster, FromServer, ToServer) < 0) {
  746.         (void)sprintf(Error, "Can't authorize with %s",
  747.         RemoteMaster ? RemoteMaster : "innd");
  748.         return Error;
  749.     }
  750.     i = OfferArticle(buff, sizeof buff, FromServer, ToServer);
  751.     }
  752.     if (i != NNTP_SENDIT_VAL) {
  753.     (void)strcpy(Error, buff);
  754.     SendQuit(FromServer, ToServer);
  755.     return Error;
  756.     }
  757.     if (Tracing)
  758.     syslog(L_TRACE, "%s post starting", ClientHost);
  759.  
  760.     /* Write the headers and a blank line. */
  761.     for (hp = Table; hp < ENDOF(Table); hp++)
  762.     if (hp->Value)
  763.         (void)fprintf(ToServer, "%s: %s\r\n", hp->Name, hp->Value);
  764.     for (i = 0; i < OtherCount; i++)
  765.     (void)fprintf(ToServer, "%s\r\n", OtherHeaders[i]);
  766.     (void)fprintf(ToServer, "\r\n");
  767.     if (FLUSH_ERROR(ToServer)) {
  768.     (void)sprintf(Error, CANTSEND, "headers", strerror(errno));
  769.     (void)fclose(FromServer);
  770.     (void)fclose(ToServer);
  771.     return Error;
  772.     }
  773.  
  774.     /* Send the article, get the server's reply. */
  775.     if (NNTPsendarticle(article, ToServer, TRUE) < 0
  776.      || fgets(buff, sizeof buff, FromServer) == NULL) {
  777.     (void)sprintf(Error, CANTSEND, "article", strerror(errno));
  778.     (void)fclose(FromServer);
  779.     (void)fclose(ToServer);
  780.     return Error;
  781.     }
  782.  
  783.     /* Did the server want the article? */
  784.     if (atoi(buff) != NNTP_TOOKIT_VAL) {
  785.     (void)strcpy(Error, buff);
  786.     SendQuit(FromServer, ToServer);
  787.     return Error;
  788.     }
  789.  
  790.     /* Send a quit and close down */
  791.     SendQuit(FromServer, ToServer);
  792.     (void)fclose(FromServer);
  793.     (void)fclose(ToServer);
  794.     if (idbuff)
  795.     (void)strcpy(idbuff, HDR(_messageid));
  796.     return NULL;
  797. }
  798.